
package com.sfeir.gwt.webding.client.component.menu;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbstractImagePrototype;

public class Item implements Serializable {
    private static final String TYPE = "type";
    private static final String URL = "url";
    private static final String LABEL = "label";
    private static final String ICON = "icon";

    /**
     * 
     */
    private static final long serialVersionUID = 1459230730728952576L;


    /**
     * Label de l'entree du menu
     */
    private String label;
    
    /**
     * Url de l'entree du menu
     */
    private String url = null;
    
    /**
     * Type du menu
     */
    private String type = null;
    
    /**
     * Icon du menu
     */
    private String icon;
    
    /**
     * Map d'options
     */
    private Map<String,String> options;
    
    /**
     * Icon du menu
     */
    private AbstractImagePrototype iconImage;
    

    /**
     * The model's parent.
     */
    protected Item parent = null;
    
    /**
     * The menu instance
     */
    private Menu menuParent = null;
    
    /**
     * The model's children.
     */
    protected List<Item> children;
    
    private Boolean open = false;
    
    public Item() {
        children = new ArrayList<Item>();
        this.icon = null;
        this.iconImage = null;
        this.options = new HashMap<String, String>();
    }
    
    
    public Item(String label) {
        this();
        this.label = label;
    }
    /**
     * Cree un item avec une map d'option
     * Il faut avoir les clès :
     * - type: Type de l'item
     * - label: Label de l'item
     * - icon: L'icone de l'item (optionnel)
     * - url: url de l'item
     * @param options
     */
    public Item(Map<String,String> options) {
        this();
        this.options = options;
        this.label = options.containsKey(LABEL) ? options.get(LABEL) : "";
        this.url = options.containsKey(URL) ? options.get(URL) : null;
        this.type = options.containsKey(TYPE) ? options.get(TYPE) : null;
        this.icon = options.containsKey(ICON) ? options.get(ICON) : null;
    }

    /**
     * 
     * @param label Label de l'item
     * @param url Url à lancer
     * @param type Type de l'item, utilisé par l'application pour différencier certains traitements. 
     */
    public Item(String label, String url, String type) {
        this();
        this.label = label;
        this.url = url;
        this.type = type;
    }
    
    /**
     * 
     * @param label Label de l'item
     * @param url Url à lancer
     * @param type Type de l'item, utilisé par l'application pour différencier certains traitements.
     * @param icon Url de l'icon de l'item 
     */
    public Item(String label, String url, String type, String icon) {
        this();
        this.label = label;
        this.url = url;
        this.type = type;
        this.icon = icon;
    }
    
    /**
     * 
     * @param label Label de l'item
     * @param url Url à lancer
     * @param type Type de l'item, utilisé par l'application pour différencier certains traitements.
     * @param iconImage icon de l'item 
     */
    public Item(String label, String url, String type, AbstractImagePrototype iconImage) {
        this();
        this.label = label;
        this.url = url;
        this.type = type;
        this.iconImage = iconImage;
    }
    
    /**
     * Retourne l'entree du menu parent
     * 
     * @return null si l'entree est racine ou non atache
     */
    public Item getParent() {
        return parent;
    }
    
    /**
     * Definie l'entree parent du menu
     * 
     * @param parent
     */
    public void setParent(Item parent) {
        this.parent = parent;
    }
    
    /**
     * Retourne le nombre de sous entree
     * @return Entier
     */
    public int getChildCount() {
        return children.size();
    }
    
    /**
     * Retourne la liste des sous entree du menu
     * 
     * @return
     */
    public List<Item> getChildren() {
        return children;
    }
    
    /**
     * Retourne la sous entree du menu a la position donnee
     * 
     * @param index
     * @return
     */
    public Item getChild(int index) {
        if ((index < 0) || (index >= children.size()))
            return null;
        return children.get(index);
    }
    
    /**
     * Ajoute une entree dans le menu
     * 
     * @param item
     */
    public void add(Item item) {
        item.setParent(this);
        children.add(item);
        onItemChange();
    }
    
    /**
     * Insere une entree dans le menu a la position donnee
     * 
     * @param item
     * @param index
     */
    public void insert(Item item, int index) {
        item.setParent(this);
        children.add(index, item);
        onItemChange();
    }
    
    /**
     * Enleve une entree du menu
     * 
     * @param item
     */
    public Item remove(Item item) {
        if (item != null && children.contains(item)) {
            item.setParent(null);
            children.remove(item);
            onItemChange();
            return item;
        }
        return null;
    }
    
    /**
     * Supprime une entree du menu a l'index donnee
     * @param index
     * @return
     */
    public Item remove(int index) {
        Item item = getChild(index);
        if (item != null) {
            item.setParent(null);
            children.remove(index);
            onItemChange();
        }
        return item;
    }

    /**
     * Supprime tous les sous menu
     * @param index
     * @return
     */
    public void removeAll() {
        for (int i = children.size() - 1; i >= 0; i--) {
            Item item = getChild(i);
            if (item != null) {
                item.setParent(null);
                children.remove(item);
                onItemChange();
            }
        }
        onItemChange();
    }
    
    /**
     * retourne vrai si l'item est filtree par le texte donne : il est affiche
     * @param item
     * @return
     */
    public boolean isFiltered(String filter) {
        if (label != null && label.toLowerCase().contains(filter)) {
            return true;
        }
        return false;
    }
    
    /**
     * Execute l'action pour l'item donnée
     * par défaut ouvre l'url dans une nouvelle page
     * peut être surchargé dans une sous classe 
     * (par exemple dans ItemProcessus pour démarer un nouveau processus)
     */
    public void exec() {
        if (url != null) {
            Window.open(url, "_blanck", "");
        }
    }
    
    /*********************************************************/
    
    public String getLabel() {
        return label;
    }
    
    public void setLabel(String label) {
        this.label = label;
    }
    
    public String getUrl() {
        return url;
    }
    
    public void setUrl(String url) {
        this.url = url;
    }
    
    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        this.type = type;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public String getIcon() {
        return icon;
    }
    
    public AbstractImagePrototype getIconImage() {
        return iconImage;
    }
    
    public void setIconImage(AbstractImagePrototype iconImage) {
        this.iconImage = iconImage;
    }

    public void setChildren(List<Item> list) {
        this.children = list;
    }

    public Map<String, String> getOptions() {
        return options;
    }
    
    public String getOption(String key) {
        return options.get(key);
    }
    
    public String setOption(String key, String value) {
        return options.put(key, value);
    }

    /**
     * Notify the parent menu to update the menu display
     */
    protected void onItemChange() {
        Item item = this;
        while (item.menuParent == null && item.parent != null) {
            item = item.parent;
        }
        if (item.menuParent != null) {
            item.menuParent.onItemChange();
        }
    }
    
    /**
     * Cette methode est utilise par la classe Menu
     * Ne pas l'utiliser
     * @param menuParent
     * @deprecated
     */
    public void setMenuParent(Menu menuParent) {
        this.menuParent = menuParent;
    }

    public void setOpen(Boolean open) {
        this.open = open;
    }

    public Boolean isOpen() {
        return open;
    }
}
